<template>
  <div class="treeTransfer">
    <!-- 左边 -->
    <div class="leftTree">
      <div class="list">
        <div class="list-menu">
          <div class="left_lowline">
            <el-checkbox
              v-model="checkedLeft"
              :disabled="leftTreeData.length < 1"
              label=""
              size="large"
              style="margin-right: 12px"
              @change="leftAllCheck"
            />
          </div>
          <!-- 搜索 -->
          <div class="left_input">
            <el-input
              v-model.trem="leftSearchText"
              class="m-2 w-50"
              placeholder="请输入部门人员名称"
              clearable
              prefix-icon="el-icon-search"
              @clear="onSearchLeft"
              @keyup.enter="onSearchLeft"
              @change="onSearchLeft"
            />
          </div>
        </div>
        <p class="left_title">{{ props.title[0] }}</p>
        <el-tree
          ref="leftTreeRef"
          :filter-node-method="filterNode"
          :data="leftTreeData"
          show-checkbox
          :node-key="props.nodeKey"
          :props="props.defaultProps"
          accordion
          @check="onCheckLeft"
          default-expand-all
        >
          <template #default="{ data }">
            <div>
              {{ data.label }}
            </div>
          </template>
        </el-tree>
      </div>
    </div>
    <!-- 中间按钮 -->
    <div class="btnDiv">
      <div class="mg10">
        <el-button
          type="primary"
          @click="toRight()"
          size="large"
          :icon="Right"
          circle
          :disabled="leftOperation.length < 1"
        />
      </div>
      <div class="mg10">
        <el-button
          type="primary"
          @click="toLeft()"
          size="large"
          :icon="Back"
          circle
          :disabled="rightOperation.length < 1"
        />
      </div>
    </div>
    <!-- 右边 -->
    <div class="rightTree">
      <div class="list">
        <div class="list-menu">
          <div class="left_lowline">
            <el-checkbox
              v-model="checkedRight"
              :disabled="rightTreeData.length < 1"
              label=""
              size="large"
              style="margin-right: 12px"
              @change="rightAllCheck"
            />
          </div>
          <!-- 搜索 -->
          <div class="left_input">
            <el-input
              v-model.trem="rightSearchText"
              class="m-2 w-50"
              placeholder="请输入部门人员名称"
              clearable
              prefix-icon="el-icon-search"
              @clear="onSearchRight"
              @keyup.enter="onSearchRight"
              @change="onSearchRight"
            />
          </div>
        </div>
        <p class="left_title">{{ props.title[1] }}</p>
        <el-tree
          ref="rightTreeRef"
          :data="rightTreeData"
          show-checkbox
          :node-key="props.nodeKey"
          :props="props.defaultProps"
          accordion
          @check="onCheckRight"
          default-expand-all
        >
          <template #default="{ data }">
            <div>
              {{ data.label }}
            </div>
          </template>
        </el-tree>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { Right, Back } from '@element-plus/icons-vue'
//@ts-nocheck    解决ts类型报红
import { ref, onMounted, watch, defineExpose } from 'vue'
import lodash from 'lodash'

const props = defineProps(['nodeKey', 'fromData', 'toData', 'defaultProps', 'title'])

const checkedLeft = ref(false)
const checkedRight = ref(false)
const leftSearchText = ref('')
const rightSearchText = ref('')
const leftOperation = ref<any[]>([])
const rightOperation = ref<any[]>([])

// 定义emit
const emits = defineEmits(['change'])
const leftTreeRef = ref()
const rightTreeRef = ref()
const childIds = ref([])
// 左侧数据
const leftTreeData = ref([])
// 右侧数据
const rightTreeData = ref([])

watch(
  props,
  (newVal) => {
    leftTreeData.value = lodash.cloneDeep(newVal.fromData)
    rightTreeData.value = lodash.cloneDeep(newVal.toData)
    setTimeout(() => {
      onCheckRight()
    }, 0)
  },
  { immediate: true }
)

watch(leftSearchText, (val) => {
  rightTreeRef.value?.filter(val)
})
watch(rightSearchText, (val) => {
  leftTreeRef.value?.filter(val)
})

onMounted(() => {
  leftSearchText.value = ''
  rightSearchText.value = ''
})

const getSelectId = (nodes?: any) => {
  let halfCheckedKeys = rightTreeRef.value.getCheckedKeys()
  nodes.forEach((node) => {
    if (halfCheckedKeys.includes(node.id) && node.pid != 0 && !childIds.value.includes(node.id)) {
      childIds.value.push(node.id)
    }
    if (node.children) {
      getSelectId(node.children)
    }
  })
}
const showChange = () => {
  getSelectId(rightTreeData.value)
}

const removeChecked = (rightList, allCheckedKeys) => {
  rightList.forEach((e, index) => {
    if (allCheckedKeys.indexOf(e.id) == -1) {
      rightList.splice(index, 1)
    }
    if (e.children) {
      removeChecked(e.children, allCheckedKeys)
    }
  })
  return rightList
}
const recursionTree = (parents, allCheckedKeys) => {
  parents.forEach((e) => {
    const list = lodash.filter(e.children, (child) => allCheckedKeys.indexOf(child.id) >= 0)
    e.children = list
    if (e.children.length !== 0) {
      recursionTree(e.children, allCheckedKeys)
    }
  })
  return parents
}
const handleData = (rightNodes, leftTree, allCheckedKeys) => {
  rightNodes.forEach((item) => {
    if (item.children) {
      let parent = leftTree.getNode(item.pid)
      let node = item
      if (!leftTree.getNode(item.id) && allCheckedKeys.indexOf(item.id) > 0) {
        const copyNode = lodash.cloneDeep(node)
        copyNode.children = []
        leftTree.append(copyNode, parent)
      }
      handleData(item.children, leftTree, allCheckedKeys)
    } else {
      let parent = leftTree.getNode(item.pid)
      let node = item
      if (!leftTree.getNode(item.id) && allCheckedKeys.indexOf(item.id) > 0) {
        leftTree.append(node, parent)
      }
    }
  })
}
// // 去右边
const toRight = async () => {
  const leftTree = leftTreeRef.value
  checkedRight.value = false
  checkedLeft.value = false
  if (!leftTree) {
    return
  }
  const leftNodes = leftTree.getCheckedNodes(false, true)
  const parents = leftNodes.filter((el) => el.children && el.children.length > 0 && el.pid == '0')
  const checkedKeys = leftTree.getCheckedKeys(false)
  const halfCheckedKeys = leftTree.getHalfCheckedKeys()
  const allCheckedKeys = halfCheckedKeys.concat(checkedKeys)
  const rightTree = rightTreeRef.value
  if (!rightTree) {
    let rightList = parents.map((parent) => {
      const obj = lodash.omit(parent, ['children'])
      obj.children = lodash.filter(
        parent.children,
        (child) => allCheckedKeys.indexOf(child.id) >= 0
      )
      return obj
    })

    let copyRightList = lodash.cloneDeep(rightList)
    removeChecked(copyRightList, allCheckedKeys)
    rightTreeData.value.push(...copyRightList)
  } else {
    let isExist = false
    rightTree.data.forEach((e) => {
      if (parents[0].id === (e as any).id) isExist = true
    })
    if (!isExist) {
      const overall = lodash.cloneDeep(parents)
      let rightList = await recursionTree(overall, allCheckedKeys)
      let copyRightList = lodash.cloneDeep(rightList)
      removeChecked(copyRightList, allCheckedKeys)
      rightTreeData.value.push(...copyRightList)
    } else {
      handleData(leftNodes, rightTree, allCheckedKeys)
    }
  }
  // 移过去之后要删除原本的值
  leftNodes.forEach((node) => {
    leftTree.setChecked(node, false, false)
    if (checkedKeys.indexOf(node.id) >= 0) {
      leftTree.remove(node)
    }
  })

  leftOperation.value = formatTree(leftTree.getCheckedNodes(false) || [], 'pid', 'id')
  // emits('change', leftTreeData.value, rightTreeData.value)

  // setTimeout(() => {
  //   rightTree?.setCheckedNodes(leftNodes)
  //   rightOperation.value = formatTree(rightTree.getCheckedNodes(false) || [], 'pid', 'id')
  // }, 500)
}
// // 去左边
const toLeft = async () => {
  checkedRight.value = false
  const rightTree = rightTreeRef.value
  if (!rightTree) {
    return
  }
  const rightNodes = rightTree.getCheckedNodes(false, true)
  const checkedKeys = rightTree.getCheckedKeys(false)
  const halfCheckedKeys = rightTree.getHalfCheckedKeys()
  const allCheckedKeys = halfCheckedKeys.concat(checkedKeys)

  const parents = lodash.filter(
    rightNodes,
    (item) => item.children && item.children.length > 0 && item.pid == '0'
  )
  const leftTree = leftTreeData.value.length ? leftTreeRef.value : null
  if (!leftTree) {
    let leftList = parents.map((parent) => {
      const obj = lodash.omit(parent, ['children'])
      obj.children = lodash.filter(
        parent.children,
        (child) => allCheckedKeys.indexOf(child.id) >= 0
      )
      return obj
    })
    let copyLeftList = lodash.cloneDeep(leftList)
    removeChecked(copyLeftList, allCheckedKeys)
    leftTreeData.value.push(...copyLeftList)
  } else {
    let isExist = false
    leftTree.data.forEach((e) => {
      if (parents[0].id === (e as any).id) isExist = true
    })
    if (!isExist) {
      const overall = lodash.cloneDeep(parents)
      let leftList = await recursionTree(overall, allCheckedKeys)
      let copyLeftList = lodash.cloneDeep(leftList)
      removeChecked(copyLeftList, allCheckedKeys)
      leftTreeData.value.push(...copyLeftList)
    } else {
      handleData(rightNodes, leftTree, allCheckedKeys)
    }
  }
  console.log(leftTreeData.value, 'slf-leftTreeData')

  rightNodes.forEach((node) => {
    rightTree.setChecked(node, false, false)
    if (checkedKeys.indexOf(node.id) >= 0) {
      rightTree.remove(node)
    }
  })

  rightOperation.value = formatTree(rightTree.getCheckedNodes(false) || [], 'pid', 'id')
  // emits('change', leftTreeData.value, rightTreeData.value)
  emits('change', rightTree.getCheckedKeys(false))
}

//左侧选中（移除原本值用）
const onCheckLeft = () => {
  leftOperation.value = formatTree(leftTreeRef.value?.getCheckedNodes(false) || [], 'pid', 'id')
}
// 右侧选中
const onCheckRight = () => {
  rightOperation.value = formatTree(rightTreeRef.value!.getCheckedNodes(false) || [], 'pid', 'id')
}

const formatTree = (tree: any[], parentKey: string = 'pid', idKey: string = 'id') => {
  // 格式化选择的树：清除全选下面的子节点
  let swap,
    parentIds: string[] = []
  // 先找出有children的id集合，再把所有的数据做对比，只要pid和其中一个对上，就把该数据删除；
  tree.forEach((item, index) => {
    if (item.children) {
      parentIds.push(item[idKey])
    }
  })
  swap = tree.filter((item, index) => {
    if (parentIds.indexOf(item[parentKey]) == -1) {
      return item
    }
  })
  return swap
}

const leftAllCheck = () => {
  const leftTree = leftTreeRef.value
  if (checkedLeft.value) {
    leftTree?.setCheckedNodes(leftTreeData.value)
    checkedLeft.value = true
  } else {
    leftTree?.setCheckedNodes([])
    checkedLeft.value = false
  }
  onCheckLeft()
}
const onSearchLeft = () => {
  leftTreeRef.value?.filter(leftSearchText.value)
}
const rightAllCheck = () => {
  const rightTree = rightTreeRef.value
  if (checkedRight.value) {
    rightTree?.setCheckedNodes(rightTreeData.value)
    checkedRight.value = true
  } else {
    rightTree?.setCheckedNodes([])
    checkedRight.value = false
  }
  onCheckRight()
}
const onSearchRight = () => {
  rightTreeRef.value!.filter(rightSearchText.value)
}
const filterNode = (value: string, data: any) => {
  if (!value) return true
  return data.username.includes(value)
}
defineExpose({
  leftTreeData,
  rightTreeData,
  showChange,
  childIds,
  rightAllCheck,
  checkedRight
})
</script>
<style lang="scss" scoped>
.treeTransfer {
  display: flex;
  width: 100%;
  justify-content: center;
}
.leftTree,
.rightTree {
  padding: 20px;
  box-sizing: border-box;
  border: 1px solid #dcdcdc;
}
.list-menu {
  display: flex;
  justify-content: center;
  align-items: center;
}
.btnDiv {
  display: flex;
  width: 100px;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 30px;
}
</style>
